//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package events_api_serv

import (
	"context"
	"fmt"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/event_dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/events/events_project"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/events_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/types/known/anypb"
)

type EventsApiImpl struct {
	events_api.UnimplementedEventsApiServer
}

func (apiImpl *EventsApiImpl) ListProjectDayStatus(ctx context.Context, req *events_api.ListProjectDayStatusRequest) (*events_api.ListProjectDayStatusResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &events_api.ListProjectDayStatusResponse{
			Code:   events_api.ListProjectDayStatusResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &events_api.ListProjectDayStatusResponse{
			Code:   events_api.ListProjectDayStatusResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &events_api.ListProjectDayStatusResponse{
			Code:   events_api.ListProjectDayStatusResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	memberUserId := ""
	if req.FilterByMemberUserId {
		memberUserId = req.MemberUserId
	}
	evStatusItemList, err := event_dao.ProjectDayEventStatusDao.List(ctx, req.ProjectId, memberUserId, req.FromDay, req.ToDay)
	if err != nil {
		return nil, err
	}
	statusItemList := []*events_api.DayEventStatusItem{}
	for _, evStatusItem := range evStatusItemList {
		if evStatusItem.EventType == int32(events_api.EVENT_TYPE_EVENT_TYPE_CUSTOM) {
			skip := false
			if projectItem.OwnerUserId == req.SessionId || roleItem.BasicInfo.Admin {
				if projectItem.Setting.HideCustomEventForAdmin {
					skip = true
				}
			} else {
				if projectItem.Setting.HideCustomEvent {
					skip = true
				}
			}
			if skip {
				continue
			}
		}
		statusItemList = append(statusItemList, evStatusItem.ToDayEventStatusItem())
	}
	return &events_api.ListProjectDayStatusResponse{
		Code:           events_api.ListProjectDayStatusResponse_CODE_OK,
		StatusItemList: statusItemList,
	}, nil
}

func (apiImpl *EventsApiImpl) ListProjectEvent(ctx context.Context, req *events_api.ListProjectEventRequest) (*events_api.ListProjectEventResponse, error) {
	emptyEventList := []*events_api.Event{}
	emptyAddonList := []*events_api.DayAddonInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &events_api.ListProjectEventResponse{
			Code:         events_api.ListProjectEventResponse_CODE_WRONG_SESSION,
			ErrMsg:       "会话不存在",
			EventList:    emptyEventList,
			DayAddonList: emptyAddonList,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &events_api.ListProjectEventResponse{
			Code:         events_api.ListProjectEventResponse_CODE_NO_PROJECT,
			ErrMsg:       "项目不存在",
			EventList:    emptyEventList,
			DayAddonList: emptyAddonList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &events_api.ListProjectEventResponse{
			Code:         events_api.ListProjectEventResponse_CODE_NO_PERMISSION,
			ErrMsg:       "没有权限",
			EventList:    emptyEventList,
			DayAddonList: emptyAddonList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	skipCustom := false
	if projectItem.OwnerUserId == req.SessionId || roleItem.BasicInfo.Admin {
		if projectItem.Setting.HideCustomEventForAdmin {
			skipCustom = true
		}
	} else {
		if projectItem.Setting.HideCustomEvent {
			skipCustom = true
		}
	}

	//列出事件
	count, err := event_dao.ProjectEventIndexDao.Count(ctx, req.ProjectId, req.FilterByMemberUserId, req.MemberUserId, true, req.FromTime, req.ToTime, skipCustom)
	if err != nil {
		return nil, err
	}
	eventItemList, err := event_dao.ProjectEventIndexDao.List(ctx, req.ProjectId,
		req.FilterByMemberUserId, req.MemberUserId, skipCustom, true, req.FromTime, req.ToTime,
		int64(req.Offset), int64(req.Limit), false)
	if err != nil {
		return nil, err
	}
	eventIdList := []string{}
	userIdList := []string{}
	for _, eventItem := range eventItemList {
		eventIdList = append(eventIdList, eventItem.EventId)
		userIdList = append(userIdList, eventItem.UserId)
	}
	eventMap, err := event_dao.EventInfoDao.ListById(ctx, eventIdList)
	if err != nil {
		return nil, err
	}

	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	evList := []*events_api.Event{}
	for _, eventItem := range eventItemList {
		eventData, ok := eventMap[eventItem.EventId]
		if !ok {
			continue
		}
		eventObj := &anypb.Any{}
		err = proto.Unmarshal(eventData.EventData, eventObj)
		if err != nil {
			return nil, err
		}
		curDisplayName := ""
		curLogoUri := ""
		userItem, ok := userItemMap[eventItem.UserId]
		if ok {
			curDisplayName = userItem.BasicInfo.DisplayName
			curLogoUri = userItem.BasicInfo.LogoUri
		}
		evList = append(evList, eventItem.ToEvent(eventObj, curDisplayName, curLogoUri))
	}
	//列出附加信息
	addonItemList, err := event_dao.DayAddonInfoDao.List(ctx, req.ProjectId, req.FromTime, req.ToTime, req.FilterByMemberUserId, req.MemberUserId)
	if err != nil {
		return nil, err
	}
	addonList := []*events_api.DayAddonInfo{}
	for _, addItem := range addonItemList {
		addon := addItem.ToDayAddonInfo()
		userItem, ok := userItemMap[addItem.UserId]
		if ok {
			addon.UserDisplayName = userItem.BasicInfo.DisplayName
			addon.UserLogoUri = userItem.BasicInfo.LogoUri
		}
		addonList = append(addonList, addon)
	}
	return &events_api.ListProjectEventResponse{
		Code:         events_api.ListProjectEventResponse_CODE_OK,
		TotalCount:   count,
		EventList:    evList,
		DayAddonList: addonList,
	}, nil
}

func (apiImpl *EventsApiImpl) ListEventByRef(ctx context.Context, req *events_api.ListEventByRefRequest) (*events_api.ListEventByRefResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &events_api.ListEventByRefResponse{
			Code:   events_api.ListEventByRefResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &events_api.ListEventByRefResponse{
			Code:   events_api.ListEventByRefResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &events_api.ListEventByRefResponse{
			Code:   events_api.ListEventByRefResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	eventItemList, err := event_dao.ProjectEventIndexDao.ListByRef(ctx, req.ProjectId, req.RefType, req.RefId)
	if err != nil {
		return nil, err
	}
	eventIdList := []string{}
	userIdList := []string{}
	for _, eventItem := range eventItemList {
		eventIdList = append(eventIdList, eventItem.EventId)
		userIdList = append(userIdList, eventItem.UserId)
	}
	eventMap, err := event_dao.EventInfoDao.ListById(ctx, eventIdList)
	if err != nil {
		return nil, err
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	evList := []*events_api.Event{}
	for _, eventItem := range eventItemList {
		eventData, ok := eventMap[eventItem.EventId]
		if !ok {
			continue
		}
		eventObj := &anypb.Any{}
		err = proto.Unmarshal(eventData.EventData, eventObj)
		if err != nil {
			return nil, err
		}
		curDisplayName := ""
		curLogoUri := ""
		userItem, ok := userItemMap[eventItem.UserId]
		if ok {
			curDisplayName = userItem.BasicInfo.DisplayName
			curLogoUri = userItem.BasicInfo.LogoUri
		}
		evList = append(evList, eventItem.ToEvent(eventObj, curDisplayName, curLogoUri))
	}
	return &events_api.ListEventByRefResponse{
		Code:      events_api.ListEventByRefResponse_CODE_OK,
		EventList: evList,
	}, nil
}

func (apiImpl *EventsApiImpl) GetEvent(ctx context.Context, req *events_api.GetEventRequest) (*events_api.GetEventResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &events_api.GetEventResponse{
			Code:   events_api.GetEventResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &events_api.GetEventResponse{
			Code:   events_api.GetEventResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &events_api.GetEventResponse{
			Code:   events_api.GetEventResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	prjEventIdxItem, err := event_dao.ProjectEventIndexDao.Get(ctx, req.ProjectId, req.EventId)
	if err != nil {
		return &events_api.GetEventResponse{
			Code:   events_api.GetEventResponse_CODE_NO_EVENT,
			ErrMsg: "事件不存在",
		}, nil
	}
	eventDataItem, err := event_dao.EventInfoDao.Get(ctx, req.EventId)
	if err != nil {
		return &events_api.GetEventResponse{
			Code:   events_api.GetEventResponse_CODE_NO_EVENT,
			ErrMsg: "事件不存在",
		}, nil
	}
	eventObj := &anypb.Any{}
	err = proto.Unmarshal(eventDataItem.EventData, eventObj)
	if err != nil {
		return nil, err
	}
	curDisplayName := ""
	curLogoUri := ""
	if prjEventIdxItem.UserId != "" {
		userItem, err := user_dao.UserInfoDao.Get(ctx, prjEventIdxItem.UserId)
		if err == nil {
			curLogoUri = userItem.BasicInfo.LogoUri
			curDisplayName = userItem.BasicInfo.DisplayName
		}
	}

	return &events_api.GetEventResponse{
		Code:  events_api.GetEventResponse_CODE_OK,
		Event: prjEventIdxItem.ToEvent(eventObj, curDisplayName, curLogoUri),
	}, nil
}

func (apiImpl *EventsApiImpl) ListEventById(ctx context.Context, req *events_api.ListEventByIdRequest) (*events_api.ListEventByIdResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &events_api.ListEventByIdResponse{
			Code:   events_api.ListEventByIdResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &events_api.ListEventByIdResponse{
			Code:   events_api.ListEventByIdResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &events_api.ListEventByIdResponse{
			Code:   events_api.ListEventByIdResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	prjEventIdxItemList, err := event_dao.ProjectEventIndexDao.ListById(ctx, req.ProjectId, req.EventIdList)
	if err != nil {
		return nil, err
	}
	eventMap, err := event_dao.EventInfoDao.ListById(ctx, req.EventIdList)
	if err != nil {
		return nil, err
	}
	userIdList := []string{}
	for _, prjEventIdxItem := range prjEventIdxItemList {
		userIdList = append(userIdList, prjEventIdxItem.UserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	evList := []*events_api.Event{}
	for _, eventItem := range prjEventIdxItemList {
		eventData, ok := eventMap[eventItem.EventId]
		if !ok {
			continue
		}
		eventObj := &anypb.Any{}
		err = proto.Unmarshal(eventData.EventData, eventObj)
		if err != nil {
			return nil, err
		}
		curDisplayName := ""
		curLogoUri := ""
		userItem, ok := userItemMap[eventItem.UserId]
		if ok {
			curDisplayName = userItem.BasicInfo.DisplayName
			curLogoUri = userItem.BasicInfo.LogoUri
		}
		evList = append(evList, eventItem.ToEvent(eventObj, curDisplayName, curLogoUri))
	}
	return &events_api.ListEventByIdResponse{
		Code:      events_api.ListEventByIdResponse_CODE_OK,
		EventList: evList,
	}, nil
}

func (apiImpl *EventsApiImpl) AddCustomEvent(ctx context.Context, req *events_api.AddCustomEventRequest) (*events_api.AddCustomEventResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &events_api.AddCustomEventResponse{
			Code:   events_api.AddCustomEventResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &events_api.AddCustomEventResponse{
			Code:   events_api.AddCustomEventResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &events_api.AddCustomEventResponse{
			Code:   events_api.AddCustomEventResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	eventData, err := anypb.New(&events_project.CustomEvent{
		EventType:    req.EventType,
		EventContent: req.EventContent,
	})
	if err != nil {
		return nil, err
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		fmt.Println(err)
		return nil, err
	}
	defer dao.EndSession(dbSess)
	ret, err := dbSess.WithTransaction(context.Background(), func(sessCtx mongo.SessionContext) (interface{}, error) {
		err := api_common.AddEvent(sessCtx, &events_api.Event{
			EventId:         uuid.NewString(),
			UserId:          sessionItem.UserId,
			UserDisplayName: sessionItem.DisplayName,
			ProjectId:       req.ProjectId,
			ProjectName:     projectItem.BasicInfo.ProjectName,
			EventType:       events_api.EVENT_TYPE_EVENT_TYPE_CUSTOM,
			EventTime:       time.Now().UnixNano() / 1e6,
			RefType:         events_api.EVENT_REF_TYPE_EVENT_REF_TYPE_PROJECT,
			RefId:           projectItem.ProjectId,
			EventData:       eventData,
		}, true, "", "")
		if err != nil {
			return nil, err
		}
		return &events_api.AddCustomEventResponse{
			Code: events_api.AddCustomEventResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*events_api.AddCustomEventResponse), nil
}
